﻿namespace Eldert.BTUG.IoT.Device.RaspberryPi2
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;

    using Libraries.Extensions;

    /// <summary>
    /// Class use to manage settings.
    /// </summary>
    internal class SettingsManagement
    {
        /// <summary>
        /// Collection which will keep track of current settings.
        /// </summary>
        private static readonly Dictionary<string, string> settings = new Dictionary<string, string>();

        /// <summary>
        /// Settings file name.
        /// </summary>
        private static string _settingsXml = "Settings.xml";

        /// <summary>
        /// Update a application setting.
        /// </summary>
        /// <param name="name">Name of the setting.</param>
        /// <param name="value">New value to be assigned to the setting.</param>
        internal static void UpdateSetting(string name, string value)
        {
            try
            {
                // Update setting
                Debug.WriteLine($"Old setting: {name} - {GetSetting(name)}");
                SetSetting(name, value);
                Debug.WriteLine($"New setting: {name} - {GetSetting(name)}");
            }
            catch (Exception exception)
            {
                exception.Log();
            }
        }

        /// <summary>
        /// Check for messages from IoT Hub with updated settings.
        /// </summary>
        internal static async void CheckForUpdatedSettings()
        {
            // Keep checking
            while (true)
            {
                // Receive updated settings from IoT Hub
                var updatedSetting = await IoTHubProxy.Receive();

                // Check if valid setting was received
                if (!string.IsNullOrWhiteSpace(updatedSetting) && updatedSetting.Split(';').Length == 2)
                {
                    // Update the setting
                    UpdateSetting(updatedSetting.Split(';')[0], updatedSetting.Split(';')[1]);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }

        /// <summary>
        /// Get the value of a setting.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        internal static string GetSetting(string name)
        {
            var settingsRetrieved = false;

            while (!settingsRetrieved)
            {

                try
                {
                    #region Create default settings file if it does not exist

                    if (!File.Exists(_settingsXml))
                    {
                        _settingsXml = Path.Combine(Path.GetTempPath(), _settingsXml);

                        if (!File.Exists(_settingsXml))
                        {
                            Debug.WriteLine("Creating default settings file...");

                            File.WriteAllText(
                                _settingsXml,
                                "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Settings><Setting Name =\"SecondsBetweenSends\" Value =\"10\" /><Setting Name =\"ShipName\" Value =\"Hydra\" /></Settings>");
                        }
                    }

                    #endregion

                    // Check if setting is already loaded
                    if (!settings.ContainsKey(name))
                    {
                        // Load setting
                        settings.Add(
                            name,
                            XDocument.Load(_settingsXml)
                                .Elements("Settings")
                                .SelectMany(element => element.Elements("Setting"))
                                .FirstOrDefault(element => element.Attribute("Name").Value == name)?.Attribute("Value")
                                .Value);
                    }

                    settingsRetrieved = true;
                }
                catch (System.Xml.XmlException)
                {
                    File.Delete(_settingsXml);
                }
            }

            return settings[name];
        }

        /// <summary>
        /// Get the value of a setting.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private static void SetSetting(string name, string value)
        {
            var document = XDocument.Load(_settingsXml);

            try
            {
                settings[name] = value;
                document.Elements("Settings")
                    .SelectMany(element => element.Elements("Setting"))
                    .FirstOrDefault(element => element.Attribute("Name").Value == name)
                    .Attribute("Value")
                    .SetValue(value);
                //document.Save(new FileStream(_settingsXml, FileMode.Open));
            }
            catch (Exception exception)
            {
                exception.Log();
            }
        }
    }
}